#pragma once
#include "Sock.hpp"
#include "Log.hpp"
#include "Epoll.hpp"
#include <cassert>
static const int default_port = 8080;
static const int g_num = 64;
class epollServer
{
public:
    epollServer(int port = default_port) : _port(port), _revs_num(g_num)
    {
        _revs = new struct epoll_event[_revs_num];
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        _epfd = Epoll::CreateEpoll();
        logMessage(DEBUG, "init success,epfd:%d,listensock:%d", _epfd, _listensock);
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
            exit(6);
        logMessage(DEBUG, "add listensock to epoll success");
    }

    void start()
    {
        int timeout = -1;
        while (true)
        {
            looponce(timeout);
        }
    }
    ~epollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_epfd >= 0)
            close(_epfd);
        if (_revs)
            delete[] _revs;
    }

private:
    void looponce(int timeout)
    {
        int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);
        switch (n)
        {
        case 0:
            logMessage(DEBUG, "timeout....");
            break;
        case -1:
            logMessage(WARNING, "epoll wait error : %s", strerror(errno));
            break;
        default:
            logMessage(DEBUG,"get a event");
            handlerEvent(n);
            break;
        }
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;
        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error!");
            return;
        }
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN))
            return;
        logMessage(DEBUG, "add new sock : %d to epoll success", sock);
    }
    void Recver(int sock)
    {
        char buffer[10240];
        int n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "echo:client[%d]# %s", sock, buffer);
        }
        else if (n == 0)
        {
            // 1.先在EPOLL中去除对sock的关心
            bool ret = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, EPOLLIN);
            assert(ret);
            (void)ret;
            // 2.关闭sock
            close(sock);
            logMessage(DEBUG, "client sock close,me too");
        }
        else
        { // 1.先在EPOLL中去除对sock的关心
            bool ret = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, EPOLLIN);
            assert(ret);
            (void)ret;
            // 2.关闭sock
            close(sock);
            logMessage(WARNING, "recv %d error",sock);
        }
    }
    void handlerEvent(int n)
    {
        assert(n > 0);
        for (int i = 0; i < n; i++)
        {
            uint32_t revent = _revs[i].events;
            int sock = _revs[i].data.fd;
            if (revent & EPOLLIN)
            {
                if (sock == _listensock)
                    Accepter();
                else
                    Recver(sock);
            }
            if (revent & EPOLLOUT)
            {
                // TODO
            }
        }
    }

private:
    int _listensock;
    uint16_t _port;
    int _epfd;
    int _revs_num;
    struct epoll_event *_revs;
};